/*
 * Statistics.h
 *
 *  Created on: 2013-01-31
 *      Author: mathieu
 */

#ifndef STATISTICS_H_
#define STATISTICS_H_

#include "semol/core/SemolExp.h" // DLL export/import defines

#include "semol/core/Sensor.h"
#include "semol/core/Actuator.h"
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <utilite/ULogger.h>
#include <list>
#include <vector>

namespace semol
{

#define RTABMAP_STATS(PREFIX, NAME, UNIT) \
	public: \
		static std::string k##PREFIX##NAME() {return #PREFIX "/" #NAME "/" #UNIT;} \
	private: \
		class Dummy##PREFIX##NAME { \
		public: \
			Dummy##PREFIX##NAME() {if(!_defaultDataInitialized)_defaultData.insert(std::pair<std::string, float>(#PREFIX "/" #NAME "/" #UNIT, 0.0f));} \
		}; \
		Dummy##PREFIX##NAME dummy##PREFIX##NAME;

class SEMOL_EXP Statistics
{
	RTABMAP_STATS(Loop, RejectedHypothesis,);
	RTABMAP_STATS(Loop, Highest_hypothesis_id,);
	RTABMAP_STATS(Loop, Highest_hypothesis_value,);
	RTABMAP_STATS(Loop, Highest_hypothesis_sim,);
	RTABMAP_STATS(Loop, Vp_hypothesis,);
	RTABMAP_STATS(Loop, Vp_likelihood,);
	RTABMAP_STATS(Loop, ReactivateId,);
	RTABMAP_STATS(Loop, Hypothesis_ratio,);
	RTABMAP_STATS(Loop, Actions_size,);
	RTABMAP_STATS(Loop, Actions_id,);
	RTABMAP_STATS(Loop, Actions_of,);
	RTABMAP_STATS(Loop, Actions_chosen,);
	RTABMAP_STATS(Loop, Hypothesis_retrieved,);

	RTABMAP_STATS(Memory, Working_memory_size,);
	RTABMAP_STATS(Memory, Short_term_memory_size,);
	RTABMAP_STATS(Memory, Sensory_memory_size,);
	RTABMAP_STATS(Memory, Nodes_transferred,);
	RTABMAP_STATS(Memory, Nodes_retrieved,);
	RTABMAP_STATS(Memory, Images_buffered,);

	RTABMAP_STATS(WeightUpdate, Id,);
	RTABMAP_STATS(WeightUpdate, SensorsMerged,);

	RTABMAP_STATS(Timing, Memory_pre_update, ms);
	RTABMAP_STATS(Timing, Memory_node_creation, ms);
	RTABMAP_STATS(Timing, Memory_weight_update, ms);
	RTABMAP_STATS(Timing, Retrieval, ms);
	RTABMAP_STATS(Timing, Add_loop_closure_link, ms);
	RTABMAP_STATS(Timing, Likelihood_computation, ms);
	RTABMAP_STATS(Timing, Posterior_computation, ms);
	RTABMAP_STATS(Timing, Hypotheses_creation, ms);
	RTABMAP_STATS(Timing, Action_selection, ms);
	RTABMAP_STATS(Timing, Statistics_creation, ms);
	RTABMAP_STATS(Timing, Memory_cleanup, ms);
	RTABMAP_STATS(Timing, Total, ms);
	RTABMAP_STATS(Timing, Forgetting, ms);
	RTABMAP_STATS(Timing, Joining_trash, ms);
	RTABMAP_STATS(Timing, Emptying_trash, ms);

public:
	static const std::map<std::string, float> & defaultData();

public:
	Statistics();
	virtual ~Statistics();

	// name format = "Grp/Name/unit"
	void addStatistic(const std::string & name, float value);

	// setters
	void setExtended(bool extended) {_extended = extended;}
	void setRefImageId(int refImageId) {_refImageId = refImageId;}
	void setLoopClosureId(int loopClosureId) {_loopClosureId = loopClosureId;}
	void setActuators(const std::list<Actuator> & actuators) {_actuators = actuators;}
	void setRefRawData(const std::list<SensorRaw> & refRawData);
	void setLoopClosureRawData(const std::list<SensorRaw> & loopClosureRawData);
	void setWeights(const std::map<int, int> & weights) {_weights = weights;}
	void setPosterior(const std::map<int, float> & posterior) {_posterior = posterior;}
	void setLikelihood(const std::map<int, float> & likelihood) {_likelihood = likelihood;}
	void setLikelihoods(const std::map<int, std::vector<float> > & likelihoods) {_likelihoods = likelihoods;}
	void setRawLikelihoods(const std::map<int, std::vector<float> > & rawLikelihoods) {_rawLikelihoods = rawLikelihoods;}
	void setRefSensorData(const std::list<std::vector<float> > & data) {_refSensorData = data;}
	void setLoopSensorData(const std::list<std::vector<float> > & data) {_loopSensorData = data;}

	// getters
	bool extended() const {return _extended;}
	int refImageId() const {return _refImageId;}
	int loopClosureId() const {return _loopClosureId;}
	const std::list<Actuator> & getActuators() const {return _actuators;}
	const std::list<SensorRaw> & refRawData() const {return _refRawData;}
	const std::list<SensorRaw> & loopClosureRawData() const {return _loopClosureRawData;}
	const std::map<int, int> & weights() const {return _weights;}
	const std::map<int, float> & posterior() const {return _posterior;}
	const std::map<int, float> & likelihood() const {return _likelihood;}
	const std::map<int, std::vector<float> > & likelihoods() const {return _likelihoods;}
	const std::map<int, std::vector<float> > & rawLikelihoods() const {return _rawLikelihoods;}
	const std::list<std::vector<float> > & refSensorData() const {return _refSensorData;}
	const std::list<std::vector<float> > & loopSensorData() const {return _loopSensorData;}

	const std::map<std::string, float> & data() const {return _data;}

private:
	int _extended; // 0 -> only loop closure and last signature ID fields are filled

	int _refImageId;
	int _loopClosureId;

	std::list<Actuator> _actuators;

	// extended data start here...
	std::list<SensorRaw> _refRawData;
	std::list<SensorRaw> _loopClosureRawData;

	std::map<int, int> _weights;
	std::map<int, float> _posterior;
	std::map<int, float> _likelihood;
	std::map<int, std::vector<float> > _likelihoods;
	std::map<int, std::vector<float> > _rawLikelihoods;

	//sm memory
	std::list<std::vector<float> > _refSensorData;
	std::list<std::vector<float> > _loopSensorData;

	// Format for statistics (Plottable statistics must go in that map) :
	// {"Group/Name/Unit", value}
	// Example : {"Timing/Total time/ms", 500.0f}
	std::map<std::string, float> _data;
	static std::map<std::string, float> _defaultData;
	static bool _defaultDataInitialized;
	// end extended data
};

} /* namespace semol */
#endif /* STATISTICS_H_ */
